/***********************************************************************************************************************
*                                                                                                                      *
* SPLASH build system v0.1                                                                                             *
*                                                                                                                      *
* Copyright (c) 2013 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                                 *
*                                                                                                                      *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                        *
*                                                                                                                      *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                           *
*                                                                                                                      *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                                                      *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                                                      *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                          *
*                                                                                                                      *
***********************************************************************************************************************/

#ifndef NocgenPLL_h
#define NocgenPLL_h

class NocgenClockNet
{
public:

	NocgenClockNet(
		std::string name = "",
		int type = NocgenClockNet::CLOCK_GLOBAL,
		int freq = 0,
		float duty = 0.5,
		float phase = 0,
		std::string refclk = "")
		: m_name(name)
		, m_type(type)
		, m_freq(freq)
		, m_duty(duty)
		, m_phase(phase)
		, m_refclk(refclk)
		, m_jitter(10)
	{
	}

	enum clock_types
	{
		CLOCK_GLOBAL,
		CLOCK_FASTIO
	};

	std::string m_name;
	int m_type;
	
	int m_freq;		//Hz
	float m_duty;	//0-1
	float m_phase;	//0-360
		
	std::string m_refclk;	//reference clock we were derived from
							//TODO: multiplier? or just derive from freq
							
	int m_jitter;	//ps
};

/**
	@brief A PLL output
 */
class NocgenPLLNet
{
public:
	NocgenPLLNet(NocgenClockNet net, int div)
		: m_outnet(net)
		, m_clkdiv(div)
	{}

	NocgenClockNet	m_outnet;
	int m_clkdiv;
};

/**
	@brief A generic phase-locked loop
 */
class NocgenPLL
{
public:
	NocgenPLL()
	{};
	
	NocgenPLL(
		const std::vector<std::string>& scriptlines,
		unsigned int& i,
		Nocgenv2GeneratedSourceNode* node,
		std::string fname);
		
	//Instance name
	std::string m_name;
	
	//The input clock
	NocgenClockNet m_input;
	
	//The output clocks
	std::vector<NocgenPLLNet> m_outputs;
	
	//Computed PLL parameters
	int m_indiv;
	int m_mult;
	
	//Flag to indicate if the clock input is differential (if so, we need to emit an IBUFGDS)
	bool m_diffinput;
	
	std::string GenerateCode(Nocgenv2GeneratedSourceNode* node);
	
protected:
	void ComputeSettings(Nocgenv2GeneratedSourceNode* node);
};

/**
	@brief Legal settings for a PLL
 */
struct NocgenPLLRestrictions
{
	NocgenDeviceFamily family;
	int speed;
	
	//Legal input frequency range
	//(from I/O clock, normal clocks are tighter)
	int inmin_mhz;
	int inmax_mhz;
	
	//Legal PFD frequency range
	int pfdmin_mhz;
	int pfdmax_mhz;
	
	//Legal VCO frequency range
	int vcomin_mhz;
	int vcomax_mhz;
	
	//Legal output frequency range
	//Max is MHz for BUFPLL, BUFGs have lower ceiling
	int outmin_khz;
	int outmax_mhz;
	
	//Maximum possible values for dividers (note, not all are legal for any particular case)
	int indivmax;	//input divider
	int vcomultmax;	//vco multiplier
	int outdivmax;	//output dividers
};


#endif

